//////////////////////////////////////////////
// AtmosphereEffect.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkAstraeus
{
	class System ;
}

namespace nkGraphics
{
	class Program ;
	class Sampler ;
	class Shader ;
	class TargetOperations ;
	class Texture ;
}

/// Includes ---------------------------------

// nkAstraeus
#include "../../../Dll/DllDefines.h"

#include "../Effect.h"

#include "AtmosphereEffectInfo.h"

// nkMemory
#include <NilkinsMemory/Pointers/UniquePtr.h>

/// Class ------------------------------------

namespace nkAstraeus
{
	class DLL_ASTRAEUS_EXPORT AtmosphereEffect final : public Effect
	{
		public :

			// Constructor, destructor
			AtmosphereEffect (System* system) noexcept ;
			virtual ~AtmosphereEffect () ;

			// Getters
			nkGraphics::Texture* getSunTransmittanceLut () const ;
			nkGraphics::Texture* getMultiScatteringLut () const ;
			nkGraphics::Texture* getSourceColorTexture () const ;
			nkGraphics::Texture* getSourceDepthTexture () const ;
			nkGraphics::Shader* getLutShader () const ;
			nkMaths::Vector getSunPosition () const ;
			nkMaths::Vector getPlanetAlbedo () const ;
			nkMaths::Vector getRayleighScattering () const ;
			nkMaths::Vector getRayleighExtinction () const ;
			nkMaths::Vector getRayleighAbsorb () const ;
			nkMaths::Vector getMieScattering () const ;
			nkMaths::Vector getMieExtinction () const ;
			nkMaths::Vector getMieAbsorb () const ;
			nkMaths::Vector getOzoneScattering () const ;
			nkMaths::Vector getOzoneExtinction () const ;
			nkMaths::Vector getOzoneAbsorb () const ;
			float getMieG () const ;
			float getRayleighHeightDensityFactor () const ;
			float getMieHeightDensityFactor () const ;
			float getOzoneHeightDensityFactor () const ;
			float getDistanceFactor () const ;
			float getSunIlluminanceFactor () const ;
			float getSunAngularRadius () const ;
			unsigned int getSunLutSampleCount () const ;
			unsigned int getMultiScatteringLutSphereSampleCount () const ;
			unsigned int getMultiScatteringLutMarchSampleCount () const ;
			unsigned int getRaymarchSampleCount () const ;
			unsigned int getSunTransmittanceLutWidth () const ;
			unsigned int getSunTransmittanceLutHeight () const ;
			unsigned int getMultiScatteringLutWidth () const ;
			unsigned int getMultiScatteringLutHeight () const ;
			SHADOW_MAP_PCF getShadowSamplingMethod () const ;
			float getShadowDepthBias () const ;
			bool getShadowDebug () const ;
			bool getUseHalfFloatForLuts () const ;
			bool getOnlyScatterOnObjects () const ;
			bool getDisplaySun () const ;

			// Setters
			void setSourceColorTexture (nkGraphics::Texture* value) ;
			void setSourceDepthTexture (nkGraphics::Texture* value) ;
			void setSunPosition (nkMaths::Vector value) ;
			void setPlanetAlbedo (nkMaths::Vector value) ;
			void setRayleighScattering (nkMaths::Vector value) ;
			void setRayleighExtinction (nkMaths::Vector value) ;
			void setRayleighAbsorb (nkMaths::Vector value) ;
			void setMieScattering (nkMaths::Vector value) ;
			void setMieExtinction (nkMaths::Vector value) ;
			void setMieAbsorb (nkMaths::Vector value) ;
			void setOzoneScattering (nkMaths::Vector value) ;
			void setOzoneExtinction (nkMaths::Vector value) ;
			void setOzoneAbsorb (nkMaths::Vector value) ;
			void setMieG (float value) ;
			void setRayleighHeightDensityFactor (float value) ;
			void setMieHeightDensityFactor (float value) ;
			void setOzoneHeightDensityFactor (float value) ;
			void setDistanceFactor (float value) ;
			void setSunIlluminanceFactor (float value) ;
			void setSunAngularRadius (float value) ;
			void setSunTransmittanceLutSampleCount (unsigned int value) ;
			void setMultiScatteringLutSphereSampleCount (unsigned int value) ;
			void setMultiScatteringLutMarchSampleCount (unsigned int value) ;
			void setRaymarchSampleCount (unsigned int value) ;
			void setShadowSource (nkGraphics::Texture* shadowMap, nkGraphics::Camera* lightCamera) ;
			void setShadowSamplingMethod (SHADOW_MAP_PCF value) ;
			void setShadowDepthBias (float value) ;
			void setShadowDebug (bool value) ;
			void setSunTransmittanceLutWidth (unsigned int value) ;
			void setSunTransmittanceLutHeight (unsigned int value) ;
			void setMultiScatteringLutWidth (unsigned int value) ;
			void setMultiScatteringLutHeight (unsigned int value) ;
			void setUseHalfFloatForLuts (bool value) ;
			void setOnlyScatterOnObjects (bool value) ;
			void setDisplaySun (bool value) ;
			void setDebugNumericalInstability (bool value) ;

			// Updates
			bool refreshLuts () ;

			// Load
			virtual bool load () override ;
			virtual void unload () override ;

		public :

			// Statics
			static nkMemory::UniquePtr<AtmosphereEffect> create (System* system = nullptr) ;

		private :

			// Functions
			// Program
			bool _prepareProgram () ;
			bool _prepareLutProgram () ;

			// Shader
			void _refillPixelConstants (nkGraphics::Shader* target) ;
			void _refillAtmosphereConstants (nkGraphics::Shader* target) ;
			bool _prepareShader () ;
			bool _prepareLutShader () ;

		private :

			// Attributes
			System* _system ;

			// Programs
			nkGraphics::Program* _program ;
			nkGraphics::Program* _lutProgram ;
			AtmosphereEffectInfo _programInfo ;

			// Shaders
			nkMemory::UniquePtr<nkGraphics::Shader> _lutShader ;

			// Info
			AtmosphereEffectInfo _info ;

			// Samplers
			nkMemory::UniquePtr<nkGraphics::Sampler> _lutSampler ;
			nkMemory::UniquePtr<nkGraphics::Sampler> _depthSampler ;
			nkMemory::UniquePtr<nkGraphics::Sampler> _shadowSampler ;

			// Textures
			nkMemory::UniquePtr<nkGraphics::Texture> _sunTransmittanceLut ;
			nkMemory::UniquePtr<nkGraphics::Texture> _multiScatteringLut ;
	} ;
}